use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

use super::enums::Freq;

/// 原始K线元素
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RawBar {
    /// 标的代码
    pub symbol: String,
    /// ID，必须是升序
    pub id: i32,
    /// 时间
    pub dt: DateTime<Utc>,
    /// 频率
    pub freq: Freq,
    /// 开盘价
    pub open: f64,
    /// 收盘价
    pub close: f64,
    /// 最高价
    pub high: f64,
    /// 最低价
    pub low: f64,
    /// 成交量
    pub vol: f64,
    /// 成交额
    pub amount: f64,
    /// 缓存，用户缓存，一个最常见的场景是缓存技术指标计算结果
    pub cache: HashMap<String, serde_json::Value>,
}

impl RawBar {
    /// 创建新的原始K线
    pub fn new(
        symbol: String,
        id: i32,
        dt: DateTime<Utc>,
        freq: Freq,
        open: f64,
        close: f64,
        high: f64,
        low: f64,
        vol: f64,
        amount: f64,
    ) -> Self {
        Self {
            symbol,
            id,
            dt,
            freq,
            open,
            close,
            high,
            low,
            vol,
            amount,
            cache: HashMap::new(),
        }
    }

    /// 上影
    pub fn upper(&self) -> f64 {
        self.high - self.open.max(self.close)
    }

    /// 下影
    pub fn lower(&self) -> f64 {
        self.open.min(self.close) - self.low
    }

    /// 实体
    pub fn solid(&self) -> f64 {
        (self.open - self.close).abs()
    }

    /// 获取缓存值
    pub fn get_cache<T>(&self, key: &str) -> Option<T>
    where
        T: for<'de> Deserialize<'de>,
    {
        self.cache.get(key).and_then(|v| serde_json::from_value(v.clone()).ok())
    }

    /// 设置缓存值
    pub fn set_cache<T>(&mut self, key: &str, value: T)
    where
        T: Serialize,
    {
        if let Ok(v) = serde_json::to_value(value) {
            self.cache.insert(key.to_string(), v);
        }
    }
}

/// 去除包含关系后的K线元素
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NewBar {
    /// 标的代码
    pub symbol: String,
    /// ID，必须是升序
    pub id: i32,
    /// 时间
    pub dt: DateTime<Utc>,
    /// 频率
    pub freq: Freq,
    /// 开盘价
    pub open: f64,
    /// 收盘价
    pub close: f64,
    /// 最高价
    pub high: f64,
    /// 最低价
    pub low: f64,
    /// 成交量
    pub vol: f64,
    /// 成交额
    pub amount: f64,
    /// 存入具有包含关系的原始K线
    pub elements: Vec<RawBar>,
    /// 缓存，用户缓存
    pub cache: HashMap<String, serde_json::Value>,
}

impl NewBar {
    /// 创建新的去除包含关系K线
    pub fn new(
        symbol: String,
        id: i32,
        dt: DateTime<Utc>,
        freq: Freq,
        open: f64,
        close: f64,
        high: f64,
        low: f64,
        vol: f64,
        amount: f64,
    ) -> Self {
        Self {
            symbol,
            id,
            dt,
            freq,
            open,
            close,
            high,
            low,
            vol,
            amount,
            elements: Vec::new(),
            cache: HashMap::new(),
        }
    }

    /// 获取原始K线列表
    pub fn raw_bars(&self) -> &[RawBar] {
        &self.elements
    }

    /// 上影
    pub fn upper(&self) -> f64 {
        self.high - self.open.max(self.close)
    }

    /// 下影
    pub fn lower(&self) -> f64 {
        self.open.min(self.close) - self.low
    }

    /// 实体
    pub fn solid(&self) -> f64 {
        (self.open - self.close).abs()
    }

    /// 获取缓存值
    pub fn get_cache<T>(&self, key: &str) -> Option<T>
    where
        T: for<'de> Deserialize<'de>,
    {
        self.cache.get(key).and_then(|v| serde_json::from_value(v.clone()).ok())
    }

    /// 设置缓存值
    pub fn set_cache<T>(&mut self, key: &str, value: T)
    where
        T: Serialize,
    {
        if let Ok(v) = serde_json::to_value(value) {
            self.cache.insert(key.to_string(), v);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use chrono::Utc;

    #[test]
    fn test_raw_bar() {
        let dt = Utc::now();
        let mut bar = RawBar::new(
            "000001.SZ".to_string(),
            1,
            dt,
            Freq::Day,
            10.0,
            12.0,
            13.0,
            9.0,
            1000.0,
            12000.0,
        );

        assert_eq!(bar.upper(), 1.0); // 13 - 12
        assert_eq!(bar.lower(), 1.0); // 10 - 9
        assert_eq!(bar.solid(), 2.0); // |10 - 12|

        // 测试缓存
        bar.set_cache("test_key", 42);
        assert_eq!(bar.get_cache::<i32>("test_key"), Some(42));
    }

    #[test]
    fn test_new_bar() {
        let dt = Utc::now();
        let bar = NewBar::new(
            "000001.SZ".to_string(),
            1,
            dt,
            Freq::Day,
            10.0,
            12.0,
            13.0,
            9.0,
            1000.0,
            12000.0,
        );

        assert_eq!(bar.upper(), 1.0);
        assert_eq!(bar.lower(), 1.0);
        assert_eq!(bar.solid(), 2.0);
        assert!(bar.raw_bars().is_empty());
    }
} 